package arisufascion.com.compone;

import java.lang.reflect.Method;


import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Gallery;
/**
 * スワイプでページめくり可能なカスタム Gallery。
 * 
 * @author Yuya Ono (IMJM)
 * @version 1.0
 */
public class SwipeableGallery extends Gallery {

	private final static String TAG = SwipeableGallery.class.getSimpleName();

	/**
	 * 子要素のクリックイベント を保持します。
	 */
	private View.OnClickListener childClickAction = null;
	private boolean childClicked = false;

	/**
	 * ページめくりを実行する内部メソッド を保持します。
	 */
	private Method scrollToChild;

	/**
	 * SwipeableGallery を初期化します。
	 * 
	 * @param context
	 */
	public SwipeableGallery(Context context) {
		this(context, null);
	}

	/**
	 * SwipeableGallery を初期化します。
	 * 
	 * @param context
	 * @param attrs
	 */
	public SwipeableGallery(Context context, AttributeSet attrs) {
		this(context, attrs, 16842864);
	}

	/**
	 * SwipeableGallery を初期化します。
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public SwipeableGallery(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		this.onInitView();
	}

	/**
	 * ビューを初期化します。
	 */
	private void onInitView() {
		try {
			this.scrollToChild = Gallery.class.getDeclaredMethod("scrollToChild", int.class);
			this.scrollToChild.setAccessible(true);
			setSpacing(-1);
		} catch (NoSuchMethodException e) {
			//throw new Exception("scrollToChild method not found!", e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.widget.Gallery#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)
	 */
	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		// スワイプイベントをオーバーライドし、ページめくり処理に置き換えます。

		try {
			
			WriteLog.i(TAG, "velocityX:" + velocityX);

			if (0 < velocityX) {
				scrollToChild.invoke(this, 0);
			} else {
				scrollToChild.invoke(this, 1);
			}

		} catch (Exception e) {
			WriteLog.e(TAG, "Gallery#scrollToChild method not found.");
		}
		return false;
	}

	/**
	 * 前の項目にスクロールします。
	 */
	public void scrollToPreviousItem() {
		this.onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(0, 0));
	}

	/**
	 * 次の項目にスクロールします。
	 */
	public void scrollToNextItem() {
		this.onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, new KeyEvent(0, 0));
	}


	/**
	 * ギャラリーの子要素にクリックイベントを設定します。
	 * 
	 * パターンA。(推奨)
	 * 
	 * @param gallery
	 * @param clickAction
	 */
	public static void setOnChildItemClickListenerA(final View clickableView, final View.OnClickListener clickAction) {
		final View.OnTouchListener touchListener = new View.OnTouchListener() {

			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				return false;
			}
		};

		clickableView.setOnTouchListener(touchListener);
	}

	/**
	 * ギャラリーの子要素にクリックイベントを設定します。
	 * 
	 * パターンB。子レイアウト個別にstate_pressedを反映させる場合はこちら。
	 * 
	 * @param clickableView
	 * @param clickAction
	 */
	public static void setOnChildItemClickListenerB(final View clickableView, final View.OnClickListener clickAction) {
		SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
			@Override
			public boolean onSingleTapUp(MotionEvent e) {
				 WriteLog.d(TAG, "onSingleTapUp.");
				clickAction.onClick(clickableView);
				return true;
			}

			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
				clickableView.setPressed(false);
				return super.onScroll(e1, e2, distanceX, distanceY);
			}

			@Override
			public boolean onSingleTapConfirmed(MotionEvent e) {
				clickableView.setPressed(false);
				return super.onSingleTapConfirmed(e);
			}
		};

		final GestureDetector gestureDetector = new GestureDetector(gestureListener);
		View.OnTouchListener touchListener = new View.OnTouchListener() {
			private boolean isProcessingTouchEvent = false;

			/*public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				return false;
			}*/

			public boolean onTouch(View v, MotionEvent event) {
				if (!isProcessingTouchEvent) {
					try {
						isProcessingTouchEvent = true;

						if (gestureDetector.onTouchEvent(event)) {
							return true;
						}

						int deltaTop = v.getTop();
						int deltaLeft = v.getLeft();

						// 親がViewでなくなるまで繰り返し辿ります。
						View currentView = v;
						View gallery = null;
						while (currentView.getParent() instanceof View) {
							View parent = (View) currentView.getParent();

							if (parent instanceof Gallery) {
								gallery = parent;
								break;
							}

							// ローカル座標の差分を計算します。
							deltaTop += parent.getTop();
							deltaLeft += parent.getLeft();

							// 次のループを親で処理します。
							currentView = parent;
						}

						// 親の中にギャラリーが見つかった場合、イベントを通知します。
						if (null != gallery) {
							MotionEvent galleryEvent = MotionEvent.obtain(event);
							galleryEvent.offsetLocation(deltaLeft, deltaTop);
							gallery.onTouchEvent(galleryEvent);
						}

					} catch (Exception e) {
						WriteLog.e(TAG, "error in " + v);
					} finally {
						isProcessingTouchEvent = false;
					}
				}

				return false;
			}
		};

		// クリックに反応しやすくなってしまうため、クリックイベントを実際にはセットしない。
		clickableView.setClickable(true);
		clickableView.setOnTouchListener(touchListener);
	}
}
